#include "DockLayout.h"

#include "DockWidgetSubsystem.h"

#include "DockableWindow.h"

#include "Widgets/Dock/DockWidgetTitleBar.h"


static const float TitleBarTopMargin = 1.f;
static const float TitleBarLeftMargin = 2.f;
static const float TitleBarMaxWidth = 200.f;

static const float SublayoutTopMargin = 0.f;
static const float SublayoutLeftMargin = 2.f;
static const float SublayoutRightMargin = 2.f;
static const float SublayoutBottomMargin = 2.f;


RDockLayout::RDockLayout()
{
    TitleBarClass=RDockWidgetTitleBar::StaticClass();

    Background = NewWidget<RRectangleWidget>(this);
    Background->Anchor.Fill(this);
    Background->FillColor = SColor::FromHexRGB(0x2D2D2D);
}

void RDockLayout::SetDirection(EDockLayoutDirection InDirection)
{
    if(Direction == InDirection)
    {
        return;
    }

    Direction = InDirection;
}

EDockLayoutDirection RDockLayout::GetDirection()
{
    return Direction;
}

void RDockLayout::DockWidget(const CString &InRegisteredWidgetName, float InSizeWeight)
{
    RWidgetPtr DockWidget=RDockWidgetSubsystem::Get()->CreateDockWidget(LayoutGroupName, InRegisteredWidgetName, this);
    
    //set parent
    DockWidget->SetParent(this);

    //create title bar
    RDockWidgetTitleBarParentPtr TitleBarParent= NewWidget<RDockWidgetTitleBarParent>(this);
    RDockWidgetTitleBarBasePtr TitleBar 
        = NewWidget<RDockWidgetTitleBarBase>(TitleBarClass.Get(),this);
    TitleBarParent->SetContent(TitleBar);
    TitleBar->SetDockWidget(DockWidget);
    
    auto TitleBackgroundMouse =TitleBarParent->BackgroundMouse;


    TitleBar->SetTitle(RDockWidgetSubsystem::Get()->GetDockWidgetTitle(LayoutGroupName,InRegisteredWidgetName));
    TitleBar->OnCloseButtonClicked().Bind([](RDockWidgetTitleBarBasePtr InTitleBar)
    {
        //get current parent dock layout
        // parent dock layout may be changed,so cant use 'this' 
        RDockLayoutPtr Layout= RDockLayoutPtr(InTitleBar->GetParent()->GetParent().Lock());
        Layout->OnDockWidgetTitleBarCloseClicked(InTitleBar->GetParent());
    });

    RDockWidgetTitleBarBaseWeakPtr TitleBarWeakPtr = TitleBar;
    RWidgetWeakPtr DockWidgetWeakPtr = DockWidget;
    TitleBackgroundMouse->OnClicked.BindLambda([TitleBarWeakPtr](const SMouseButtonEvent& MouseEvent)->bool
    {
        RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock());

        if(DragingLayout->Direction!=EDockLayoutDirection::Stacked)
        {
            return false;
        }

        //select this title 
        for(int32_t i=0;i<DragingLayout->DockedWidgets.Num();i++)
        {
            if(DragingLayout->DockedWidgets[i].Title == TitleBarWeakPtr->GetParent())
            {
                DragingLayout->SelectedIndexInStack=i;
                return true;
            }
        }

        assert(false&& "should not go herer, title bar not found");
        return true;
    });


    TitleBackgroundMouse->Drag->OnDragStarted.Bind([DockWidgetWeakPtr,TitleBarWeakPtr]()
    {
        //use shared ptr to prevent title destroyed
        RDockWidgetTitleBarBasePtr TitleBar=TitleBarWeakPtr.Lock();
        RWindowPtr OldWindow= TitleBar->GetWindow();

        //get current parent dock layout
        // parent dock layout may be changed,so cant use 'this' 
        RDockLayoutPtr Layout= RDockLayoutPtr(TitleBar->GetParent()->GetParent().Lock()); 

        //check if can drag current window or create new one
        bool bUseCurrentWindow = false;

        if(OldWindow->IsA<RDockableWindow>())
        {
            RDockableWindowPtr DockableWindow = RDockableWindowPtr(OldWindow);
            if(DockableWindow->GetRootLayout()==Layout)
            {
                bUseCurrentWindow=true;
            }
        }
        



        RWindowPtr DragingWindow = nullptr;
        if(bUseCurrentWindow)
        {
            DragingWindow=OldWindow;

            Layout->SetCloseWindowWhenLastDockedWidgetRemoved(false);
        }
        else
        {
            auto DockableWindow= NewObject<RDockableWindow>();
            DragingWindow= DockableWindow;

            DockableWindow->Show();

            auto DockedWidget=Layout->RemoveDockedWidget(TitleBar->GetParent());

            DockableWindow->SetWindowSize(DockedWidget.Widget->PresentSize);
            DockableWindow->SetWindowPosition(TitleBar->PresentAbsPosition);
            
            //create layout 
            RDockLayoutPtr NewLayout = DockableWindow->GetRootLayout();
            NewLayout->Anchor.Fill(DragingWindow->GetRootWidget());
            NewLayout->SetDirection(EDockLayoutDirection::Stacked);
            NewLayout->SetGroupName(Layout->GetGroupName());

            //move the title bar to new window ,so cant continue drag
            NewLayout->DockWidget(DockedWidget);

        }

        DragingWindow->SetOpcity(0.7f);
        DragingWindow->StartCaptureMouse();

    });

    TitleBackgroundMouse->Drag->OnDragMoved.Bind([this,DockWidgetWeakPtr,TitleBarWeakPtr](const SVec2& TotalMove)
    {

        //find a dock layout under mouse
        RWindowPtr Window = RDockWidgetTitleBarBasePtr(TitleBarWeakPtr)->GetWindow();
        RWindowWeakPtr WindowWeakPtr = Window;
        Window->SetOpcity(0.7f);
        RDockLayoutPtr DragingLayout= RDockLayoutPtr(
            TitleBarWeakPtr->GetParent()->GetParent().Lock()); 

        DragingLayout->bIsOverridingTitleBar=false;


        auto DockLayoutUnderMouse = RDockWidgetSubsystem::Get()->FindDockLayoutUnderMouse(DragingLayout->GetGroupName(), Window);

        auto LetWindowFollowMouse= [WindowWeakPtr]()
        {
            WindowWeakPtr->SetWindowPosition(SMouseButtonEvent::GetMosuePositionOnScreen());
        };

        if(!DockLayoutUnderMouse)
        {
            //make the root window follow the mouse
            LetWindowFollowMouse();
            return;
        }



        //check if mouse is in border of layout
        //if mouse is in border, dock to on side of all docked widgets
        {
            auto TargetLayoutPosition = DockLayoutUnderMouse->GetPresentAbsolutePosition()
                +DockLayoutUnderMouse->GetWindow()->GetWindowPosition().ToVec2();
            auto TargetLayoutSize = DockLayoutUnderMouse->GetPresentSize();

            auto MousePosition = SMouseButtonEvent::GetMosuePositionOnScreen().ToVec2()-TargetLayoutPosition;
            const float BorderWidth = 5.f;

            float UpDistance = MousePosition.Y;
            float DownDistance = TargetLayoutSize.Y - MousePosition.Y;
            float LeftDistance = MousePosition.X;
            float RightDistance = TargetLayoutSize.X - MousePosition.X;

            float MinDistance = CMathBase::Min(UpDistance,DownDistance);
            MinDistance = CMathBase::Min(MinDistance,LeftDistance);
            MinDistance = CMathBase::Min(MinDistance,RightDistance);

            if(MinDistance<BorderWidth)
            {
                SIntPoint NewWindowPosition;
                SIntPoint NewWindowSize;
                if(MinDistance==UpDistance)
                {
                    NewWindowPosition=TargetLayoutPosition;
                    NewWindowSize=SIntPoint(TargetLayoutSize.X,TargetLayoutSize.Y/2);
                }
                else if(MinDistance==DownDistance)
                {
                    NewWindowPosition=TargetLayoutPosition+ SVec2(0,TargetLayoutSize.Y/2);
                    NewWindowSize=SIntPoint(TargetLayoutSize.X,TargetLayoutSize.Y/2);
                }
                else if(MinDistance==LeftDistance)
                {
                    NewWindowPosition=TargetLayoutPosition;
                    NewWindowSize=SIntPoint(TargetLayoutSize.X/2,TargetLayoutSize.Y);
                }
                else //if(MinDistance==RightDistance)
                {
                    NewWindowPosition=TargetLayoutPosition+ SVec2(TargetLayoutSize.X/2,0);
                    NewWindowSize=SIntPoint(TargetLayoutSize.X/2,TargetLayoutSize.Y);
                }

                Window->SetWindowPosition(NewWindowPosition);
                Window->SetWindowSize(NewWindowSize);
                return;
            }

        }

        //is mouse is in title bar area, should copy the title bars and insert draging titlebar
        //makes looks like insert into a stacked layout
        switch(DockLayoutUnderMouse->GetDirection())
        {
            case EDockLayoutDirection::Stacked:
            {
                
                SRect TitleBarArea(DockLayoutUnderMouse->GetPresentAbsolutePosition()
                    ,SVec2(DockLayoutUnderMouse->GetPresentSize().X,TitleBarTopMargin+TitleBarWeakPtr->GetPresentSize().Y));
                
                if(TitleBarArea.IsPointIn(DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()))
                {
                    int32_t TotalTitleNumAfterPlace= DockLayoutUnderMouse->DockedWidgets.Num()+1;
                    float TitleBarWidthAfterPlace;
                    {
                        TitleBarWidthAfterPlace = CMathBase::Min(TitleBarArea.Extent.X/TotalTitleNumAfterPlace,TitleBarMaxWidth);
                    }
                    float MouseRelativeX=DockLayoutUnderMouse->GetWindow()->GetMousePosition().X -TitleBarArea.Min.X;

                    DragingLayout->DragingTitleBarIndex=CMathBase::Min(
                        (int32_t)(MouseRelativeX/TitleBarWidthAfterPlace),TotalTitleNumAfterPlace-1);
                    
                    
                    //remove extra title bars or add new title bars
                    while(DragingLayout->ExtraTitleBars.Num()> (TotalTitleNumAfterPlace-1))
                    {
                        auto TitleBar=DragingLayout->ExtraTitleBars.Pop();
                        DragingLayout->RemoveSubWidget(TitleBar);
                    }

                    while(DragingLayout->ExtraTitleBars.Num()< (TotalTitleNumAfterPlace-1))
                    {
                        auto TitleBar= NewWidget<RDockWidgetTitleBarParent>(DragingLayout);
                        auto TitleBarContent= NewWidget<RDockWidgetTitleBarBase>(TitleBarClass.Get(),DragingLayout);
                        TitleBar->SetContent(TitleBarContent);
                        DragingLayout->ExtraTitleBars.Add(TitleBar);
                    }

                    //copy title bar text
                    for(int32_t i=0;i<DragingLayout->ExtraTitleBars.Num();i++)
                    {
                        DragingLayout->ExtraTitleBars[i]->Content->SetTitle(
                            DockLayoutUnderMouse->DockedWidgets[i].Title->Content->GetTitle());
                    }


                    DragingLayout->bIsOverridingTitleBar=true;
                    

                    //put draging window cover target layout
                    Window->SetWindowPosition(
                        DockLayoutUnderMouse->GetPresentAbsolutePosition()
                        + DockLayoutUnderMouse->GetWindow()->GetWindowPosition().ToVec2());
                    Window->SetWindowSize(DockLayoutUnderMouse->GetPresentSize());
                    Window->SetOpcity(1.f);
                    return;
                }

            }
            break;

            case EDockLayoutDirection::Horizontal:
            case EDockLayoutDirection::Vertical:
            {
                //check is mouse in titile bar
                SRect HovoredTitleBarArea;
                int32_t HovorDockedWidgetIndex=-1;
                SVec2 MousePosition =DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2();
                for(int32_t i=0; i<DockLayoutUnderMouse->DockedWidgets.Num();i++)
                {
                    if(!DockLayoutUnderMouse->DockedWidgets[i].Title)
                    {
                        continue;
                    }
                    
                    SRect TitleBarArea;
                    if(DockLayoutUnderMouse->GetDirection()==EDockLayoutDirection::Horizontal)
                    {
                        TitleBarArea.Min.X = DockLayoutUnderMouse->WidgetPositions[i]+ DockLayoutUnderMouse->GetPresentAbsolutePosition().X;
                        TitleBarArea.Min.Y = DockLayoutUnderMouse->GetPresentAbsolutePosition().Y;

                        TitleBarArea.Extent.X= DockLayoutUnderMouse->WidgetSizes[i];
                        TitleBarArea.Extent.Y= TitleBarTopMargin+TitleBarHeight;
                    }
                    else
                    {
                        TitleBarArea.Min.X = DockLayoutUnderMouse->GetPresentAbsolutePosition().X;
                        TitleBarArea.Min.Y = DockLayoutUnderMouse->WidgetPositions[i] + DockLayoutUnderMouse->GetPresentAbsolutePosition().Y;

                        TitleBarArea.Extent.X= DockLayoutUnderMouse->GetPresentSize().X;
                        TitleBarArea.Extent.Y= TitleBarTopMargin+TitleBarHeight;
                    }

                    if(TitleBarArea.IsPointIn(MousePosition))
                    {
                        HovorDockedWidgetIndex =i;
                        HovoredTitleBarArea = TitleBarArea;
                        break;
                    }
                }

                if(HovorDockedWidgetIndex!=-1)
                {
                    SRect TitleBarArea= HovoredTitleBarArea;
                   
                    const int32_t TotalTitleNumAfterPlace=2;
                    float TitleBarWidthAfterPlace= 
                        CMathBase::Min(TitleBarArea.Extent.X/TotalTitleNumAfterPlace,TitleBarMaxWidth);
                    
                    float MouseRelativeX=DockLayoutUnderMouse->GetWindow()->GetMousePosition().X -TitleBarArea.Min.X;

                    //prepare ExtraTitleBars    
                    //remove extra title bars or add new title bars
                    while(DragingLayout->ExtraTitleBars.Num()> 1)
                    {
                        auto TitleBar=DragingLayout->ExtraTitleBars.Pop();
                        DragingLayout->RemoveSubWidget(TitleBar);
                    }

                    if(DragingLayout->ExtraTitleBars.Num()< 1)
                    {
                        auto TitleBar= NewWidget<RDockWidgetTitleBarParent>(DragingLayout);
                        auto TitleBarContent= NewWidget<RDockWidgetTitleBarBase>(TitleBarClass.Get(),DragingLayout);
                        TitleBar->SetContent(TitleBarContent);
                        DragingLayout->ExtraTitleBars.Add(TitleBar);
                    }
                    assert(DragingLayout->ExtraTitleBars.Num()==1);

                    DragingLayout->DragingTitleBarIndex=CMathBase::Min(
                        (int32_t)(MouseRelativeX/TitleBarWidthAfterPlace),TotalTitleNumAfterPlace-1);
                    
                    //copy title bar text
                    DragingLayout->ExtraTitleBars[0]->Content->SetTitle(
                        DockLayoutUnderMouse->DockedWidgets[HovorDockedWidgetIndex].Title->Content->GetTitle());

                    DragingLayout->bIsOverridingTitleBar=true;

                    //put draging window cover target layout
                    SVec2 NewWindowPositon=
                        DockLayoutUnderMouse->GetPresentAbsolutePosition()+ DockLayoutUnderMouse->GetWindow()->GetWindowPosition().ToVec2();
                    SVec2 NewWindowSize= DockLayoutUnderMouse->GetPresentSize();

                    if(DockLayoutUnderMouse->GetDirection()==EDockLayoutDirection::Horizontal)
                    {
                        NewWindowPositon.X += DockLayoutUnderMouse->WidgetPositions[HovorDockedWidgetIndex];
                        NewWindowSize.X= DockLayoutUnderMouse->WidgetSizes[HovorDockedWidgetIndex];
                    }
                    else
                    {
                        NewWindowPositon.Y += DockLayoutUnderMouse->WidgetPositions[HovorDockedWidgetIndex];
                        NewWindowSize.Y= DockLayoutUnderMouse->WidgetSizes[HovorDockedWidgetIndex];
                    }

                    Window->SetWindowPosition(NewWindowPositon);
                    Window->SetWindowSize(NewWindowSize);
                    Window->SetOpcity(1.f);
                    return;
                }

            }
            break;

        }
        


        //find content widget under mouse
        SVec2 TargetSize;
        SVec2 TargetWindowPosition;
        bool bFound = false;

        for(auto& Tuple: DockLayoutUnderMouse->DockedWidgets)
        {
            if(!Tuple.Title)
            {
                //this is a layout , impossible to be under mouse
                continue;
            }

            TargetSize= Tuple.Widget ->GetPresentSize();
            TargetWindowPosition= Tuple.Widget ->GetPresentAbsolutePosition();

            SRect TargetWidgetRect = SRect(TargetWindowPosition,TargetSize);
            
            auto MousePostion= DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2();
            if(TargetWidgetRect.IsPointIn(MousePostion))
            {
                //mouse in this widget
                bFound = true;
                break;
            }
        }

        if(!bFound)
        {
            //might in title bar area or in spliter area

            //make the root window follow the mouse
            Window->SetWindowPosition(SMouseButtonEvent::GetMosuePositionOnScreen());
            return;
        }

        assert(bFound && "mouse is not in any docked widget");

        //determine which side to dock
        //SVec2 TargetSize= DockLayoutUnderMouse->GetPresentSize();
        SVec2 MousePositionInTarget =
            DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()-TargetWindowPosition;

        //split the target layout into 5 parts 
        //up,down,left,right,center
        //center is a center square
        //up,down,left,right seperate the left area into 4 parts
        //find the nearest part

        SVec2 NormalizedMousePosition= MousePositionInTarget / TargetSize;

        //chec is mouse in center
        if(NormalizedMousePosition.X>0.25f && NormalizedMousePosition.X<0.75f
        && NormalizedMousePosition.Y>0.25f && NormalizedMousePosition.Y<0.75f)
        {
            //mouse in center
            //make the root window follow the mouse
            Window->SetWindowPosition(SMouseButtonEvent::GetMosuePositionOnScreen());
            return;
        }

        float UpDistance = NormalizedMousePosition.Y;
        float DownDistance = 1 - NormalizedMousePosition.Y;
        float LeftDistance = NormalizedMousePosition.X;
        float RightDistance = 1 - NormalizedMousePosition.X;

        float MinDistance = CMathBase::Min(UpDistance,DownDistance);
        MinDistance = CMathBase::Min(MinDistance,LeftDistance);
        MinDistance = CMathBase::Min(MinDistance,RightDistance);

        SIntPoint NewWindowPosition;
        SIntPoint NewWindowSize;
        if(MinDistance == UpDistance)
        {
            //dock to up
            NewWindowPosition = DockLayoutUnderMouse->GetWindow()->GetWindowPosition() + 
                TargetWindowPosition;

            NewWindowSize = SIntPoint(TargetSize.X,TargetSize.Y/2);
        }
        else if(MinDistance == DownDistance)
        {
            //dock to down
            NewWindowPosition = DockLayoutUnderMouse->GetWindow()->GetWindowPosition() + 
                TargetWindowPosition + SIntPoint(0,TargetSize.Y/2);

            NewWindowSize = SIntPoint(TargetSize.X,TargetSize.Y/2);
        }
        else if(MinDistance == LeftDistance)
        {
            //dock to left
            NewWindowPosition = DockLayoutUnderMouse->GetWindow()->GetWindowPosition() + 
                TargetWindowPosition;

            NewWindowSize = SIntPoint(TargetSize.X/2,TargetSize.Y);
        }
        else if(MinDistance == RightDistance)
        {
            //dock to right
            NewWindowPosition = DockLayoutUnderMouse->GetWindow()->GetWindowPosition() + 
                TargetWindowPosition + SIntPoint(TargetSize.X/2,0);

            NewWindowSize = SIntPoint(TargetSize.X/2,TargetSize.Y);

        }

        Window->SetWindowPosition(NewWindowPosition);
        Window->SetWindowSize(NewWindowSize);
        

    });

    TitleBackgroundMouse->Drag->OnDragEnded.Bind([this,DockWidgetWeakPtr,TitleBarWeakPtr]()
    {

        //find a dock layout under mouse
        RWindowPtr Window = RDockWidgetTitleBarBasePtr(TitleBarWeakPtr)->GetWindow();
        RWindowWeakPtr WindowWeakPtr = Window;
        RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock()); 
        auto DockLayoutUnderMouse = RDockWidgetSubsystem::Get()->FindDockLayoutUnderMouse(DragingLayout->GetGroupName(),Window);

        //remove override title bars
        DragingLayout->bIsOverridingTitleBar=false;
        for(auto& OverrideTitleBar: DragingLayout->ExtraTitleBars)
        {
            DragingLayout->RemoveSubWidget(OverrideTitleBar);
        }
        DragingLayout->ExtraTitleBars.Clear();

        //clear the anchor to root widget
        //TODO  fix bug that root widget still be a valid refferecd in anchor when window closed 
        //DragingLayout->Anchor.Clear();

        RDockLayoutWeakPtr DragingLayoutWeakPtr= DragingLayout;
        auto DropWidnow= [WindowWeakPtr,DragingLayoutWeakPtr]()
        {
            DragingLayoutWeakPtr->Anchor.Fill(WindowWeakPtr->GetRootWidget());
            DragingLayoutWeakPtr->SetCloseWindowWhenLastDockedWidgetRemoved(true);
            WindowWeakPtr->SetOpcity(1.f);
            WindowWeakPtr->StopCaptureMouse();
        };

        if(!DockLayoutUnderMouse)
        {
            DropWidnow();
            return;
        }

        //check if mouse is in border of layout
        //if mouse is in border, dock to on side of all docked widgets
        {
            auto TargetLayoutPosition = DockLayoutUnderMouse->GetPresentAbsolutePosition();
            auto TargetLayoutSize = DockLayoutUnderMouse->GetPresentSize();

            auto MousePosition = DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()-TargetLayoutPosition;
            const float BorderWidth = 5.f;

            float UpDistance = MousePosition.Y;
            float DownDistance = TargetLayoutSize.Y - MousePosition.Y;
            float LeftDistance = MousePosition.X;
            float RightDistance = TargetLayoutSize.X - MousePosition.X;

            float MinDistance = CMathBase::Min(UpDistance,DownDistance);
            MinDistance = CMathBase::Min(MinDistance,LeftDistance);
            MinDistance = CMathBase::Min(MinDistance,RightDistance);

            if(MinDistance<BorderWidth)
            {
                EDockLayoutDirection NewLayoutDirection = MinDistance == UpDistance || MinDistance == DownDistance ? EDockLayoutDirection::Vertical : EDockLayoutDirection::Horizontal;
                bool bBecomeFirstWidget = MinDistance == UpDistance || MinDistance == LeftDistance;

                RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock()); 

                //create a layout and copy all docked widgets to it
                RDockLayoutPtr NewLayout = NewWidget<RDockLayout>(DockLayoutUnderMouse->GetParent().Lock());
                RDockLayout::MoveDockedWidgets(DockLayoutUnderMouse,NewLayout,true);

                DockLayoutUnderMouse->SetDirection(NewLayoutDirection);

                if(bBecomeFirstWidget)
                {
                    //move the darging layout to DockLayoutUnderMouse
                    RDockLayout::MoveDockedWidgets(DragingLayout,DockLayoutUnderMouse,false);

                    //dock NewLayout to  DockLayoutUnderMouse
                    DockLayoutUnderMouse->DockLayout(NewLayout);
                }
                else
                {
                    DockLayoutUnderMouse->DockLayout(NewLayout);

                    //move the darging layout to NewLayout
                    RDockLayout::MoveDockedWidgets(DragingLayout,DockLayoutUnderMouse,false);
                }
                NewLayout->SameDirectionMergeToParentLayout();
                

                

                //close the window
                Window->Close();
                return;
            }

        }

        //is mouse is in title bar area, should copy the title bars and insert draging titlebar
        //makes looks like insert into a stacked layout  
        switch(DockLayoutUnderMouse->GetDirection())
        {
            case EDockLayoutDirection::Stacked:
            {
                
                SRect TitleBarArea(DockLayoutUnderMouse->GetPresentAbsolutePosition()
                    ,SVec2(DockLayoutUnderMouse->GetPresentSize().X,TitleBarTopMargin+TitleBarWeakPtr->GetPresentSize().Y));
                
                if(TitleBarArea.IsPointIn(DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()))
                {
                    int32_t TotalTitleNumAfterPlace= DockLayoutUnderMouse->DockedWidgets.Num()+1;
                    float TitleBarWidthAfterPlace;
                    {
                        TitleBarWidthAfterPlace = CMathBase::Min(TitleBarArea.Extent.X/TotalTitleNumAfterPlace,TitleBarMaxWidth);
                    }
                    float MouseRelativeX=DockLayoutUnderMouse->GetWindow()->GetMousePosition().X -TitleBarArea.Min.X;

                    auto DragingTitleBarIndex=CMathBase::Min(
                        (int32_t)(MouseRelativeX/TitleBarWidthAfterPlace),TotalTitleNumAfterPlace-1);
                    
                    //insert draging title bar
                    DockLayoutUnderMouse->DockedWidgets.Insert(DragingTitleBarIndex
                        ,DragingLayout->DockedWidgets[0]);

                    DockLayoutUnderMouse->SelectedIndexInStack=DragingTitleBarIndex;

                    DragingLayout->DockedWidgets[0].Widget->SetParent(DockLayoutUnderMouse.Get());
                    DragingLayout->DockedWidgets[0].Title->SetParent(DockLayoutUnderMouse.Get());
                    DragingLayout->DockedWidgets.Clear();
                    
                    Window->Close();
                    return;
                }

            }
            break;

            case EDockLayoutDirection::Horizontal:
            case EDockLayoutDirection::Vertical:
            {
                //check is mouse in titile bar

                SRect HovoredTitleBarArea;
                int32_t HovorDockedWidgetIndex=-1;
                SVec2 MousePosition =DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()
                    ;
                for(int32_t i=0; i<DockLayoutUnderMouse->DockedWidgets.Num();i++)
                {
                    if(!DockLayoutUnderMouse->DockedWidgets[i].Title)
                    {
                        continue;
                    }
                    
                    SRect TitleBarArea;
                    if(DockLayoutUnderMouse->GetDirection()==EDockLayoutDirection::Horizontal)
                    {
                        TitleBarArea.Min.X = DockLayoutUnderMouse->WidgetPositions[i]+DockLayoutUnderMouse->GetPresentAbsolutePosition().X;
                        TitleBarArea.Min.Y = DockLayoutUnderMouse->GetPresentAbsolutePosition().Y;

                        TitleBarArea.Extent.X= DockLayoutUnderMouse->WidgetSizes[i];
                        TitleBarArea.Extent.Y= TitleBarTopMargin+TitleBarHeight;
                    }
                    else
                    {
                        TitleBarArea.Min.X = DockLayoutUnderMouse->GetPresentAbsolutePosition().X;
                        TitleBarArea.Min.Y = DockLayoutUnderMouse->WidgetPositions[i]+DockLayoutUnderMouse->GetPresentAbsolutePosition().Y;

                        TitleBarArea.Extent.X= DockLayoutUnderMouse->GetPresentSize().X;
                        TitleBarArea.Extent.Y= TitleBarTopMargin+TitleBarHeight;
                    }

                    if(TitleBarArea.IsPointIn(MousePosition))
                    {
                        HovorDockedWidgetIndex =i;
                        HovoredTitleBarArea=TitleBarArea;
                        break;
                    }
                }

                if(HovorDockedWidgetIndex!=-1)
                {
                    SRect TitleBarArea=HovoredTitleBarArea;
                   
                    const int32_t TotalTitleNumAfterPlace=2;
                    float TitleBarWidthAfterPlace= 
                        CMathBase::Min(TitleBarArea.Extent.X/TotalTitleNumAfterPlace,TitleBarMaxWidth);
                    
                    float MouseRelativeX=DockLayoutUnderMouse->GetWindow()->GetMousePosition().X -TitleBarArea.Min.X;

                    int32_t DragingTitleBarIndex=CMathBase::Min(
                        (int32_t)(MouseRelativeX/TitleBarWidthAfterPlace),TotalTitleNumAfterPlace-1);
                    
                    //use draging layout to replace the target docked widget
                    switch(DragingTitleBarIndex)
                    {
                        case 0:
                        {
                            auto TempTuple=  DockLayoutUnderMouse->DockedWidgets[HovorDockedWidgetIndex];
                            
                            DockLayoutUnderMouse->DockedWidgets[HovorDockedWidgetIndex]=SDockedWidget(DragingLayout,1.f);
                            DragingLayout->SetParent(DockLayoutUnderMouse.Get());

                            DragingLayout->DockedWidgets.Add(TempTuple);
                            TempTuple.Widget->SetParent(DragingLayout.Get());
                            TempTuple.Title->SetParent(DragingLayout.Get());
                        }
                        break;

                        case 1:
                        {
                            auto TempTuple=  DockLayoutUnderMouse->DockedWidgets[HovorDockedWidgetIndex];
                            DockLayoutUnderMouse->DockedWidgets[HovorDockedWidgetIndex]=SDockedWidget(DragingLayout,1.f);
                            DragingLayout->SetParent(DockLayoutUnderMouse.Get());

                            DragingLayout->DockedWidgets.Insert(0,TempTuple);
                            TempTuple.Widget->SetParent(DragingLayout.Get());
                            TempTuple.Title->SetParent(DragingLayout.Get());
                        }
                        break;

                        default:
                            assert(false);
                        break;
                    }
                    DragingLayout->SelectedIndexInStack=DragingTitleBarIndex;

                    Window->Close();
                    return;
                }

            }
            break;

        }
        
        //find content widget under mouse
        SVec2 TargetSize;
        SVec2 TargetWindowPosition;
        bool bFound = false;

        uint32_t DockedWidgetIndex = -1;
        for(auto& Tuple: DockLayoutUnderMouse->DockedWidgets)
        {
            DockedWidgetIndex++;

            if(!Tuple.Title)
            {
                //this is a layout , impossible to be under mouse
                continue;
            }

            TargetSize= Tuple.Widget ->GetPresentSize();
            TargetWindowPosition= Tuple.Widget ->GetPresentAbsolutePosition();

            SRect TargetWidgetRect = SRect(TargetWindowPosition,TargetSize);
            
            auto MousePostion= DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2();
            if(TargetWidgetRect.IsPointIn(MousePostion))
            {
                //mouse in this widget
                bFound = true;
                break;
            }
        }

        if(!bFound)
        {
            //might in title bar area or in spliter area

            Window->SetOpcity(1.f);
            Window->StopCaptureMouse();
            return;
        }

        assert(bFound && "mouse is not in any docked widget");

        //determine which side to dock
        //SVec2 TargetSize= DockLayoutUnderMouse->GetPresentSize();
        SVec2 MousePositionInTarget =
            DockLayoutUnderMouse->GetWindow()->GetMousePosition().ToVec2()-TargetWindowPosition;

        //split the target layout into 5 parts 
        //up,down,left,right,center
        //center is a center square
        //up,down,left,right seperate the left area into 4 parts
        //find the nearest part

        SVec2 NormalizedMousePosition= MousePositionInTarget / TargetSize;

        //check is mouse in center
        if(NormalizedMousePosition.X>0.25f && NormalizedMousePosition.X<0.75f
        && NormalizedMousePosition.Y>0.25f && NormalizedMousePosition.Y<0.75f)
        {
            //mouse in center
            Window->SetOpcity(1.f);
            Window->StopCaptureMouse();
            return;
        }

        float UpDistance = NormalizedMousePosition.Y;
        float DownDistance = 1 - NormalizedMousePosition.Y;
        float LeftDistance = NormalizedMousePosition.X;
        float RightDistance = 1 - NormalizedMousePosition.X;

        float MinDistance = CMathBase::Min(UpDistance,DownDistance);
        MinDistance = CMathBase::Min(MinDistance,LeftDistance);
        MinDistance = CMathBase::Min(MinDistance,RightDistance);

        EDockLayoutDirection NewLayoutDirection= MinDistance == UpDistance || MinDistance == DownDistance ? EDockLayoutDirection::Vertical : EDockLayoutDirection::Horizontal;
        bool bBecomeFirstWidget = MinDistance == UpDistance || MinDistance == LeftDistance;

        if(DockLayoutUnderMouse->GetDirection()== EDockLayoutDirection::Stacked)
        {
            //create a new dock layout
            RDockLayoutPtr NewDownLayout = NewWidget<RDockLayout>(DockLayoutUnderMouse);

            //move the docked widget to new layout
            RDockLayout::MoveDockedWidgets(
                DockLayoutUnderMouse,NewDownLayout,true);

            
            DockLayoutUnderMouse->SetDirection(NewLayoutDirection);

            if(bBecomeFirstWidget)
            {
                //move the darging layout to DockLayoutUnderMouse
                RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock()); 
                RDockLayout::MoveDockedWidgets(
                    DragingLayout,DockLayoutUnderMouse,false);
                //DockLayoutUnderMouse->SizeWeights.Add(1.f);

                //dock NewDownLayout to  DockLayoutUnderMouse
                DockLayoutUnderMouse->DockLayout(NewDownLayout);
            }
            else
            {
                DockLayoutUnderMouse->DockLayout(NewDownLayout);

                //move the darging layout to NewDownLayout
                RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock());
                RDockLayout::MoveDockedWidgets(
                    DragingLayout,DockLayoutUnderMouse,false);
            }

            DockLayoutUnderMouse->SameDirectionMergeToParentLayout();

        }
        else
        {
            //create a new dock layout
            RDockLayoutPtr DragingLayout= RDockLayoutPtr(TitleBarWeakPtr->GetParent()->GetParent().Lock()); 
            DragingLayout->SetDirection(NewLayoutDirection);

            auto DockedWidgetTuple= DockLayoutUnderMouse->DockedWidgets[DockedWidgetIndex];
            
            if(bBecomeFirstWidget)
            {
                DragingLayout->DockWidget(DockedWidgetTuple,false);
            }
            else
            {
                DragingLayout->DockWidget(DockedWidgetTuple,true);
            }

            DragingLayout->SetParent(DockLayoutUnderMouse.Get());
        
            DockLayoutUnderMouse->DockedWidgets[DockedWidgetIndex] =SDockedWidget(DragingLayout,1.f);

            DragingLayout->SameDirectionMergeToParentLayout();
        }

        Window->Close();

    });
    
    //add to docked widgets
    DockedWidgets.Add(
        SDockedWidget(
            DockWidget
            ,InRegisteredWidgetName
            ,TitleBar->GetParent()
            ,InSizeWeight));
}

void RDockLayout::DockWidget(const SDockedWidget& InDockedWidget,bool bToFirst)
{
    InDockedWidget.Widget->Anchor.Clear();
    InDockedWidget.Title->Anchor.Clear();
    
    InDockedWidget.Widget->SetParent(this);
    InDockedWidget.Title->SetParent(this);

    //add to docked widgets
    if(bToFirst)
    {
        DockedWidgets.Insert(0,InDockedWidget);
    }
    else
    {
        //add to docked widgets
        DockedWidgets.Add(InDockedWidget);
    }

    //SizeWeights.Add(1.f);
}

void RDockLayout::DockLayout(RDockLayoutPtr InAnotherDockWidget,float SizeWeight)
{
    assert(Direction!=EDockLayoutDirection::Stacked && "can not dock a layout  to a stacked layout");
    assert(InAnotherDockWidget && "widget is null");
    assert(InAnotherDockWidget != this && "can not dock self");

    //set parent
    InAnotherDockWidget->SetParent(this);

    InAnotherDockWidget->SetGroupName(LayoutGroupName);

    //add to docked widgets
    DockedWidgets.Add(SDockedWidget(RWidgetPtr(InAnotherDockWidget),SizeWeight));
    
}

void RDockLayout::Undock(RWidgetPtr InDockWidget)
{
    assert(InDockWidget && "widget is null");
    assert(InDockWidget != this && "can not undock self");

    //find docked widget
    auto Index = DockedWidgets.FindBy([InDockWidget](const SDockedWidget& InTuple)
    {
        return InTuple.Widget == InDockWidget;
    });

    assert(Index.HasValue() && "widget is not docked");

    SDockedWidget Docked = DockedWidgets[Index.GetValue()];

    //remove from docked widgets
    DockedWidgets.RemoveAt(Index.GetValue());

    Docked.Widget->SetParent(nullptr);
    if(Docked.Title)
    {
        Docked.Title->SetParent(nullptr);
    }
}

TVector<RWidgetPtr> RDockLayout::GetDockedWidgetsAndLayouts()
{
    TVector<RWidgetPtr> Result;
    for(auto& Tuple : DockedWidgets)
    {
        Result.Add(Tuple.Widget);
    }
    return Result;
}

int32_t RDockLayout::GetDockedWidgetsAndLayoutsNum()
{
    return DockedWidgets.Num();
}

RWidgetPtr RDockLayout::GetDockedWidgetsOrLayout(int32_t InIndex)
{
    return DockedWidgets[InIndex].Widget;
}

float RDockLayout::GetSizeWeight(int32_t InIndex)
{
    return DockedWidgets[InIndex].SizeWeight;
}

CString RDockLayout::GetDockedWidgetName(int32_t InIndex)
{
    return DockedWidgets[InIndex].WidgetName;
}

bool RDockLayout::HasDockedWidget(CString InRegisteredWidgetName)
{
    for(auto& Tuple : DockedWidgets)
    {
        if(Tuple.WidgetName == InRegisteredWidgetName)
        {
            return true;
        }
    }
    return false;
}

void RDockLayout::SetSelectedWidgetInStack(const CString &InRegisteredWidgetName)
{
    assert(Direction==EDockLayoutDirection::Stacked && "only stacked layout can set selected widget");
    for(int32_t i=0;i<DockedWidgets.Num();i++)
    {
        if(DockedWidgets[i].WidgetName == InRegisteredWidgetName)
        {
            SelectedIndexInStack=i;
            return;
        }
    }
}

void RDockLayout::SetSelectedIndexInStack(int32_t InIndex)
{
    assert(Direction==EDockLayoutDirection::Stacked && "only stacked layout can set selected widget");
    SelectedIndexInStack=InIndex;
}

int32_t RDockLayout::GetSelectedIndexInStack()
{
    return SelectedIndexInStack;
}

void RDockLayout::SetCloseWindowWhenLastDockedWidgetRemoved(bool InValue)
{
    bCloseWindowWhenLastDockedWidgetRemoved=InValue;
}

void RDockLayout::SetGroupName(const CString &InGroupName)
{
    LayoutGroupName=InGroupName;

    //set all child layout group name
    for(auto& Tuple : DockedWidgets)
    {
        if(Tuple.Widget->IsA<RDockLayout>())
        {
            RDockLayoutPtr Layout = RDockLayoutPtr(Tuple.Widget);
            Layout->SetGroupName(InGroupName);
        }
    }
}

const CString &RDockLayout::GetGroupName()
{
    return LayoutGroupName;
}

void RDockLayout::CalculateChildrenPresentPositionAndSize()
{
    Background->CalculatePresentPositionAndSize();

    //make sure enough spliter
    switch(Direction)
    {
        case EDockLayoutDirection::Stacked:
        {
            //destroy all spliters
            for(auto Spliters : Spliters)
            {
                RemoveSubWidget(Spliters);
            }
            Spliters.Clear();
            SpliterMouses.Clear();
        }
        break;

        case EDockLayoutDirection::Horizontal:
        {

            //destroy extra spliters
            while(Spliters.Num()>DockedWidgets.Num()-1 )
            {
                RemoveSubWidget(Spliters.Last());
                Spliters.RemoveAt(Spliters.Num()-1);
                SpliterMouses.RemoveAt(SpliterMouses.Num()-1);
            }
           

            for(int i=0;i<DockedWidgets.Num()-1;i++)
            {
                RRectangleWidgetPtr Spliter = nullptr;
                RMouseWidgetPtr SpliterMouse = nullptr;
                if(i<Spliters.Num())
                {
                    //already have spliter
                    Spliter = Spliters[i];
                    SpliterMouse = SpliterMouses[i];
                }
                else
                {
                    Spliter = NewWidget<RRectangleWidget>(this);
                    Spliter->FillColor = SColor::FromHexRGB(0x4D4D4D);
                    Spliters.Add(Spliter);

                    //create mouse widget
                    SpliterMouse = NewWidget<RMouseWidget>(Spliter);
                    SpliterMouse->Anchor.Fill(Spliter);
                    SpliterMouse->Drag->bIsEnabled=true;
                    SpliterMouse->Drag->Target=(Spliter);
                    SpliterMouses.Add(SpliterMouse);
                }



                Spliter->Anchor.Clear();
                Spliter->Anchor.VerticalFill(this);

                SpliterMouse->CursorShape = EMouseCursorType::ResizeHorizontal;
                SpliterMouse->Drag->Direction = EDragDirection::Horizontal;


                RRectangleWidgetWeakPtr SpliterWeakPtr = Spliter;
                RMouseWidgetWeakPtr SpliterMouseWeakPtr = SpliterMouse;

                SpliterMouse->Drag->OnDragStarted = [this,SpliterWeakPtr,i,SpliterMouseWeakPtr]()
                {   
                    SpliterMouseWeakPtr->Drag->TargetWidgetMinX =WidgetPositions[i];
                    SpliterMouseWeakPtr->Drag->TargetWidgetMaxX = WidgetPositions[i+1]+ WidgetSizes[i+1];
                };

                SpliterMouse->Drag->OnDragMoved = [this,SpliterWeakPtr,i](const SVec2& TotalMove)
                {
                    //recalculate sizeweights

                    float SpliterPos= SpliterWeakPtr->X.Get();
                    float NewFormerDockWidgetSize=SpliterPos-DockedWidgets[i].Widget->X.Get();
                    float FormerWidgetPercent= NewFormerDockWidgetSize /(WidgetSizes[i+0]+WidgetSizes[i+1]-this->SpliterWidth);
                    
                    float TotalWeight= DockedWidgets[i].SizeWeight+DockedWidgets[i+1].SizeWeight;
                    DockedWidgets[i].SizeWeight=TotalWeight*FormerWidgetPercent;
                    DockedWidgets[i+1].SizeWeight=TotalWeight-DockedWidgets[i].SizeWeight;
                };
            }
        
            break;
        }

        case EDockLayoutDirection::Vertical:
        {
            //destroy extra spliters
            while(Spliters.Num()>DockedWidgets.Num()-1 )
            {
                RemoveSubWidget(Spliters.Last());
                Spliters.RemoveAt(Spliters.Num()-1);
                SpliterMouses.RemoveAt(SpliterMouses.Num()-1);
            }
           

            for(int i=0;i<DockedWidgets.Num()-1;i++)
            {
                RRectangleWidgetPtr Spliter = nullptr;
                RMouseWidgetPtr SpliterMouse = nullptr;
                if(i<Spliters.Num())
                {
                    //already have spliter
                    Spliter = Spliters[i];
                    SpliterMouse = SpliterMouses[i];
                }
                else
                {
                    Spliter = NewWidget<RRectangleWidget>(this);
                    Spliter->FillColor = SColor::FromHexRGB(0x4D4D4D);
                    Spliters.Add(Spliter);

                    //create mouse widget
                    SpliterMouse = NewWidget<RMouseWidget>(Spliter);
                    SpliterMouse->Anchor.Fill(Spliter);
                    SpliterMouse->Drag->bIsEnabled=true;
                    SpliterMouse->Drag->Target=(Spliter);
                    SpliterMouses.Add(SpliterMouse);
                }

                Spliter->Anchor.Clear();
                Spliter->Anchor.HorizontalFill(this);

                SpliterMouse->CursorShape = EMouseCursorType::ResizeVertical;
                SpliterMouse->Drag->Direction = EDragDirection::Vertical;

                RRectangleWidgetWeakPtr SpliterWeakPtr = Spliter;
                RMouseWidgetWeakPtr SpliterMouseWeakPtr = SpliterMouse;

                SpliterMouse->Drag->OnDragStarted = [this,SpliterWeakPtr,i,SpliterMouseWeakPtr]()
                {   
                    SpliterMouseWeakPtr->Drag->TargetWidgetMinY =WidgetPositions[i];
                    SpliterMouseWeakPtr->Drag->TargetWidgetMaxY = WidgetPositions[i+1]+ WidgetSizes[i+1];
                };

                SpliterMouse->Drag->OnDragMoved = [this,SpliterWeakPtr,i](const SVec2& TotalMove)
                {
                    //recalculate sizeweights

                    float SpliterPos= SpliterWeakPtr->Y.Get();
                    float NewFormerDockWidgetSize=SpliterPos-DockedWidgets[i].Widget->Y.Get()
                        + TitleBarHeight +TitleBarTopMargin;
                    float FormerWidgetPercent= NewFormerDockWidgetSize /(WidgetSizes[i+0]+WidgetSizes[i+1]);
                    
                    float TotalWeight= DockedWidgets[i].SizeWeight+DockedWidgets[i+1].SizeWeight;
                    DockedWidgets[i].SizeWeight=TotalWeight*FormerWidgetPercent;
                    DockedWidgets[i+1].SizeWeight=TotalWeight-DockedWidgets[i].SizeWeight;

                    
                };
            }
            break;
        }
    }


    switch(Direction)
    {
        case EDockLayoutDirection::Stacked:
        {
            if(bIsOverridingTitleBar)
            {


                float TitleBarWidth = 
                    (PresentSize.X - TitleBarLeftMargin * (ExtraTitleBars.Num()-1+1))
                    / ExtraTitleBars.Num();
                TitleBarWidth=CMathBase::Min(TitleBarWidth,TitleBarMaxWidth);

                float CurrentTitleBarPos=0;
                for(int32_t TitileIndex=0;TitileIndex<ExtraTitleBars.Num();TitileIndex ++)
                {
                
                    if(TitileIndex==DragingTitleBarIndex)
                    {
                        //keep blank for draging title bar
                        CurrentTitleBarPos+=TitleBarWidth+TitleBarLeftMargin;
        
                    }

                    ExtraTitleBars[TitileIndex]->X=CurrentTitleBarPos;
                    CurrentTitleBarPos+=TitleBarWidth+TitleBarLeftMargin;
    
                    ExtraTitleBars[TitileIndex]->Y=TitleBarTopMargin;
                    ExtraTitleBars[TitileIndex]->Width=TitleBarWidth;
                    ExtraTitleBars[TitileIndex]->Height=TitleBarHeight;
                    ExtraTitleBars[TitileIndex]->CalculatePresentPositionAndSize();

                }

                assert(DockedWidgets.Num()==1);

                DockedWidgets[0].Title->X=GetWindow()->GetMousePosition().X-PresentAbsPosition.X- TitleBarWidth/2;
                DockedWidgets[0].Title->Y=TitleBarTopMargin;
                DockedWidgets[0].Title->Width=TitleBarWidth;
                DockedWidgets[0].Title->Height=TitleBarHeight;
                DockedWidgets[0].Title->CalculatePresentPositionAndSize();
            }

            //if no docked widget, do nothing
            if(DockedWidgets.Num()==0)
            {
                return;
            }

            //put all title bar on top 
            if(!bIsOverridingTitleBar)
            {
                float TitleBarWidth = 
                    (PresentSize.X - TitleBarLeftMargin * (DockedWidgets.Num()-1))
                    / DockedWidgets.Num();
                TitleBarWidth=CMathBase::Min(TitleBarWidth,TitleBarMaxWidth);

                float NextTitleBarX = 0;
                for(auto& Tuple : DockedWidgets)
                {
                    //title bar
                    Tuple.Title->X=NextTitleBarX;
                    Tuple.Title->Y=TitleBarTopMargin;
                    Tuple.Title->Width=TitleBarWidth;
                    Tuple.Title->Height=TitleBarHeight;
                    Tuple.Title->CalculatePresentPositionAndSize();
                    NextTitleBarX+=TitleBarWidth  + TitleBarLeftMargin;
                }
            }

            //make content widget shared the same size 
            {
                for(auto& Tuple : DockedWidgets)
                {
                    Tuple.Widget->X= 0;
                    Tuple.Widget->Y= Tuple.Title->Y.Get()+ Tuple.Title->Height.Get() + SublayoutTopMargin;
                    Tuple.Widget->Width=PresentSize.X;
                    Tuple.Widget->Height=PresentSize.Y - Tuple.Widget->Y.Get();

                    Tuple.Widget->CalculatePresentPositionAndSize();
                }
            }

            break;
        }

        case EDockLayoutDirection::Horizontal:
        {
            //if no docked widget, do nothing
            if(DockedWidgets.Num()==0)
            {
                return;
            }

            WidgetSizes.Clear();
            WidgetSizes.Reserve(DockedWidgets.Num());
            WidgetPositions.Clear();
            WidgetPositions.Resize(DockedWidgets.Num());

            float TotalWeight= 0.f;
            for(auto& DockedWidget : DockedWidgets)
            {
                TotalWeight+=DockedWidget.SizeWeight;
            }
            for(auto& DockedWidget : DockedWidgets)
            {
                WidgetSizes.Add(DockedWidget.SizeWeight/TotalWeight * (PresentSize.X - SpliterWidth* (DockedWidgets.Num()-1)));
            }

            WidgetPositions[0]=0.f;
            for(int32_t i=1;i<WidgetPositions.Num();i++)
            {
                WidgetPositions[i]=WidgetPositions[i-1]+WidgetSizes[i-1]+SpliterWidth;
            }
            
            for(int32_t i=0;i<DockedWidgets.Num();i++)
            {
                auto& Tuple = DockedWidgets[i];
                if(Tuple.Title)
                {
                    //this is not layout

                    //place title bar
                    Tuple.Title->X=TitleBarLeftMargin+WidgetPositions[i];
                    Tuple.Title->Y=TitleBarTopMargin;
                    Tuple.Title->Width=CMathBase::Min(TitleBarMaxWidth,WidgetSizes[i]);
                    Tuple.Title->Height=TitleBarHeight;
                    Tuple.Title->CalculatePresentPositionAndSize();

                    //place content
                    Tuple.Widget->X=WidgetPositions[i];
                    Tuple.Widget->Width=WidgetSizes[i];

                    Tuple.Widget->Y=Tuple.Title->Y.Get()+ Tuple.Title->Height.Get() + SublayoutTopMargin;
                    Tuple.Widget->Height=PresentSize.Y - Tuple.Widget->Y.Get() ;

                    Tuple.Widget->CalculatePresentPositionAndSize();
                }
                else
                {
                    //this is layout
                    Tuple.Widget->X=WidgetPositions[i]+ SublayoutLeftMargin;
                    Tuple.Widget->Y=0.f;
                    Tuple.Widget->Width=WidgetSizes[i] - SublayoutRightMargin - SublayoutLeftMargin;
                    Tuple.Widget->Height=PresentSize.Y - SublayoutBottomMargin;
                    Tuple.Widget->CalculatePresentPositionAndSize();
                }

                if(i<DockedWidgets.Num()-1)
                {
                    //this is not last widget
                    //place spliter
                    Spliters[i]->X=WidgetPositions[i]+WidgetSizes[i];
                    Spliters[i]->Width=SpliterWidth;
                    Spliters[i]->CalculatePresentPositionAndSize();
                }
            }

            break;
        }

        case EDockLayoutDirection::Vertical:
        {
            //if no docked widget, do nothing
            if(DockedWidgets.Num()==0)
            {
                return;
            }

            WidgetSizes.Clear();
            WidgetSizes.Reserve(DockedWidgets.Num());
            WidgetPositions.Clear();
            WidgetPositions.Resize(DockedWidgets.Num());

            float TotalWeight= 0.f;
            for(auto& DockedWidget : DockedWidgets)
            {
                TotalWeight+=DockedWidget.SizeWeight;
            }
            for(auto& DockedWidget : DockedWidgets)
            {
                WidgetSizes.Add(DockedWidget.SizeWeight/TotalWeight * (PresentSize.Y - SpliterWidth* (DockedWidgets.Num()-1)));
            }

            WidgetPositions[0]=0.f;
            for(int32_t i=1;i<WidgetPositions.Num();i++)
            {
                WidgetPositions[i]=WidgetPositions[i-1]+WidgetSizes[i-1]+SpliterWidth;
            }


            for(int32_t i=0;i<DockedWidgets.Num();i++)
            {
                auto& Tuple = DockedWidgets[i];
                if(Tuple.Title)
                {
                    //this is not layout

                    //place title bar
                    Tuple.Title->X=TitleBarLeftMargin;
                    Tuple.Title->Y=TitleBarTopMargin+WidgetPositions[i];
                    Tuple.Title->Width=CMathBase::Min(TitleBarMaxWidth,PresentSize.X);
                    Tuple.Title->Height=TitleBarHeight;
                    Tuple.Title->CalculatePresentPositionAndSize();

                    //place content
                    Tuple.Widget->X=0.f;
                    Tuple.Widget->Width=PresentSize.X;

                    Tuple.Widget->Y=Tuple.Title->Y.Get()+ Tuple.Title->Height.Get() + SublayoutTopMargin;

                    Tuple.Widget->Height=WidgetSizes[i]
                        -(TitleBarTopMargin+ Tuple.Title->Height.Get())
                         -SublayoutTopMargin;

                    Tuple.Widget->CalculatePresentPositionAndSize();
                }
                else
                {
                    //this is layout
                    Tuple.Widget->X=SublayoutLeftMargin;
                    Tuple.Widget->Y=WidgetPositions[i];
                    Tuple.Widget->Width=PresentSize.X-SublayoutLeftMargin-SublayoutRightMargin;
                    Tuple.Widget->Height=WidgetSizes[i]-SublayoutBottomMargin;
                    Tuple.Widget->CalculatePresentPositionAndSize();
                }

                if(i<DockedWidgets.Num()-1)
                {
                    //this is not last widget
                    //place spliter
                    Spliters[i]->Y=WidgetPositions[i]+WidgetSizes[i];
                    Spliters[i]->Height=SpliterWidth;
                    Spliters[i]->CalculatePresentPositionAndSize();
                }
            }

            break;
        }
  
    }

}

void RDockLayout::PaintSubWidgets( uint16_t &InZOrder)
{
    Background->Paint(InZOrder);

    if(Direction==EDockLayoutDirection::Stacked)
    {
        if(DockedWidgets.Empty())
        {
            return;
        }

        int32_t SelectedIndex= CMathBase::Clamp(SelectedIndexInStack,0,DockedWidgets.Num()-1);

        DockedWidgets[SelectedIndex].Widget->Paint(InZOrder);

        for(int32_t i=0;i<DockedWidgets.Num();i++)
        {
            if(i==SelectedIndex)
            {
                DockedWidgets[i].Title->Content->Highlight();
            }
            else
            {
                DockedWidgets[i].Title->Content->Unhighlight();
            }

            DockedWidgets[i].Title->Paint(InZOrder);
        }
    }
    else
    {
        for(auto& Tuple: DockedWidgets)
        {
            Tuple.Widget->Paint(InZOrder);
            if(Tuple.Title)
            {
                Tuple.Title->Content->Highlight();
                Tuple.Title->Paint(InZOrder);
            }
        }
    }

    for(auto Spliter : Spliters)
    {
        Spliter->Paint(InZOrder);
    }

    if(bIsOverridingTitleBar)
    {
        for(auto & OverrideTitle : ExtraTitleBars)
        {
            OverrideTitle->Paint(InZOrder);
        }
    }
}

void RDockLayout::OnDockWidgetTitleBarCloseClicked(RDockWidgetTitleBarParentPtr InTitleBar)
{
    RemoveDockedWidget(InTitleBar);
}

RDockLayout::SDockedWidget RDockLayout::RemoveDockedWidget(RDockWidgetTitleBarParentPtr InTitleBar)
{
    //find docked widget
    auto Index = DockedWidgets.FindBy([InTitleBar](const SDockedWidget& InTuple)
    {
        return InTuple.Title == InTitleBar;
    });

    assert(Index.HasValue() && "widget is not docked");

    SDockedWidget Tuple = DockedWidgets[Index.GetValue()];

    RWidgetPtr DockedWidget = Tuple.Widget;

    RWindowPtr Window = InTitleBar->GetWindow();

    switch(Direction)
    {
        case EDockLayoutDirection::Stacked:
        {

            Undock(DockedWidget);

            //if no docked widget, undock self
            if(DockedWidgets.Num()==0)
            {
                if(GetParent()->IsA<RDockLayout>())
                {
                    RDockLayoutPtr ParentDockLayout = RDockLayoutPtr(GetParent().Get());
                    ParentDockLayout->Undock(this);
                }
            }
            else if (DockedWidgets.Num()==1)
            {
                MergeToParentLayout();
            }

            break;
        }

        case EDockLayoutDirection::Horizontal:
        case  EDockLayoutDirection::Vertical:
        {
            Undock(DockedWidget);

            if(DockedWidgets.Num()==0)
            {
                //this is the root dock layout, do nothing
                SetDirection(EDockLayoutDirection::Stacked);
                return Tuple;
            }

            if(DockedWidgets.Num()==1)
            {
                if(DockedWidgets[0].Widget->IsA<RDockLayout>())
                {
                    //move the left layout's docked widget to self
                    // RDockLayoutPtr DockLayout = RDockLayoutPtr(DockedWidgets[0].Widget);
                    // DockLayout->
                    MergeToParentLayout();

                }
                else 
                {
                    SetDirection(EDockLayoutDirection::Stacked);
                    MergeToParentLayout();
                }
            }


            break;
        }

    }

    if(this->bCloseWindowWhenLastDockedWidgetRemoved && DockedWidgets.Num()==0)
    {
        Window->Close();
    }

    return Tuple;
}

void RDockLayout::MergeToParentLayout()
{
    //if parent is dock layout, 
    //and this is the only docked widget of parent or this layout only have one docked widget
    //merge to parent
    if(!GetParent()->IsA<RDockLayout>()  || DockedWidgets.Num()!=1 )
    {
        return;
    }
    
    RDockLayoutPtr ParentDockLayout = RDockLayoutPtr(GetParent().Get());
    RWidgetPtr Self = this;

    int32_t IndexInParent=-1;
    for(int32_t i=0;i<ParentDockLayout->DockedWidgets.Num();i++)
    {
        if(ParentDockLayout->DockedWidgets[i].Widget == Self)
        {
            IndexInParent=i;
            break;
        }
    }
    assert(IndexInParent!=-1);

    auto TempTuple=  ParentDockLayout->DockedWidgets[IndexInParent];
    ParentDockLayout->RemoveSubWidget(TempTuple.Widget);
    assert(!TempTuple.Title);

    float OldSizeWeight= ParentDockLayout->DockedWidgets[IndexInParent].SizeWeight;
    ParentDockLayout->DockedWidgets[IndexInParent]=DockedWidgets[0];
    if(ParentDockLayout->DockedWidgets.Num()!=1)
    {
        //keep size
        ParentDockLayout->DockedWidgets[IndexInParent].SizeWeight=OldSizeWeight;
    }

    DockedWidgets[0].Widget->SetParent(ParentDockLayout.Get());
    if(DockedWidgets[0].Title)
    {
        DockedWidgets[0].Title->SetParent(ParentDockLayout.Get());
    }
    DockedWidgets.Clear();

    if(ParentDockLayout->DockedWidgets.Num()==1)
    {
        //copy size and direction
        ParentDockLayout->SetDirection(Direction);
    }

    //try merge to parent's parent
    ParentDockLayout->MergeToParentLayout();
}

void RDockLayout::SameDirectionMergeToParentLayout()
{
    //if this layout have same direction with parent
    //move all docked widget to parent

    if(!GetParent()->IsA<RDockLayout>()  || Direction != RDockLayoutPtr(GetParent().Get())->Direction)
    {
        return;
    }
    
    RDockLayoutPtr ParentDockLayout = RDockLayoutPtr(GetParent().Get());
    RWidgetPtr Self = this;

    int32_t IndexInParent=-1;
    for(int32_t i=0;i<ParentDockLayout->DockedWidgets.Num();i++)
    {
        if(ParentDockLayout->DockedWidgets[i].Widget == Self)
        {
            IndexInParent=i;
            break;
        }
    }

    assert(IndexInParent!=-1);
    ParentDockLayout->DockedWidgets.RemoveAt(IndexInParent);

    //reverse iterate all docked widget
    for(int32_t i=DockedWidgets.Num()-1;i>=0;i--)
    {
        auto TempTuple=  DockedWidgets[i];

        ParentDockLayout->DockedWidgets.Insert(IndexInParent,TempTuple);
        
        TempTuple.Widget->SetParent(ParentDockLayout.Get());
        if(TempTuple.Title)
        {
            TempTuple.Title->SetParent(ParentDockLayout.Get());
        }


    }

    ParentDockLayout->SameDirectionMergeToParentLayout();

    DockedWidgets.Clear();
    this->SetParent(nullptr);
}

void RDockLayout::MoveDockedWidgets(
    RDockLayoutPtr InFromLayout
    , RDockLayoutPtr InToLayout
    ,bool CopyDirectionAndPercent
    )
{
    //move the docked widget to parent
    auto DockedWidgets = InFromLayout->DockedWidgets;
    if(!CopyDirectionAndPercent)
    {
        for(auto& DockedWidget : DockedWidgets)
        {
            DockedWidget.SizeWeight=1.f;
        }
    }
    InToLayout->DockedWidgets.Append(DockedWidgets);

    for(auto& Tuple : DockedWidgets)
    {
        Tuple.Widget->Anchor.Clear();
        Tuple.Widget->SetParent(InToLayout.Get());
        if(Tuple.Title)
        {
            Tuple.Title->Anchor.Clear();
            Tuple.Title->SetParent(InToLayout.Get());
        }
    }    

    InFromLayout->DockedWidgets.Clear();


    if(CopyDirectionAndPercent)
    {
        //InToLayout->SizeWeights.Append(InFromLayout->SizeWeights);//  FirstWidgetPercent=InFromLayout->FirstWidgetPercent;
        InToLayout->SetDirection(InFromLayout->Direction);
    }

}
